package common

import (
	"encoding/json"
	"fmt"
	"math"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"sync"
	"time"

	"gitee.com/tomatomeatman/golang-repository/bricks3/function/data/jsonutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/data/sequenceutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/data/stringutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/data/u64util"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/fileutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/reflectutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/model/dbinfo"
	"gitee.com/tomatomeatman/golang-repository/bricks3/model/globalvariable"
	"gitee.com/tomatomeatman/golang-repository/bricks3/utils/sqlfactory"
	Log "github.com/cihub/seelog"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"gopkg.in/ini.v1"
)

var (
	recordKeyJam     = "" //创建sRecordKey用的干扰串
	recordKeyJamOnce sync.Once

	addRemoveNames       []string          //新增时需要排除的字段(不允许前端传入)
	addValidIgnoreNames  []string          //新增时检验的忽略字段
	editRemoveNames      []string          //修改时需要排除的字段(不允许前端传入)
	editValidIgnoreNames []string          //修改时检验的忽略字段
	likeQueryIgnoreNames map[string]string //like查询时忽略的字段

	addRemoveNamesOnce       sync.Once
	addValidIgnoreNamesOnce  sync.Once
	editRemoveNamesOnce      sync.Once
	editValidIgnoreNamesOnce sync.Once
	likeQueryIgnoreNamesOnce sync.Once
)

/**
 * 初始化
 */
func init() {
	globalvariable.Add("Module@VirtualService", NewService())
}

// VirtualService 通用业务服务
type VirtualService struct {
	DbName    string
	TableName string
}

type ServicBusinessInfo struct {
	EnableTag              int      `json:"enableTag"`              //控制操作,首位9不参与用7个数代表开关,0为不限制,1为限制;"90000001,
	CheckRepeatCombination []string `json:"checkRepeatCombination"` //检查待新增内容是否存在重复数据(多字段组合重复即重复)集合,[]string",
	CheckRepeatAlone       []string `json:"checkRepeatAlone"`       //检查待新增内容是否存在重复数据(单独字段重复即重复)集合,map[string]int,注意:int必须是1、10、100、1000",
}

func GetService(dbName, tableName string) *VirtualService {
	return &VirtualService{
		DbName:    dbName,
		TableName: tableName,
	}
}

// NewService 创建通用业务服务
func NewService() *VirtualService {
	return &VirtualService{}
}

// func (s *VirtualService) DoMethod(ctx *gin.Context, tableName string, method string, params map[string]interface{}) (bool, string, interface{}) {

// }

// FindById 根据ID查询
func (s *VirtualService) FindById(ctx *gin.Context, refer *dbinfo.TableInfo, id interface{}, fields []string) (bool, string, interface{}) {
	columns := []string{}
	for _, v := range fields {
		k := refer.GetFieldName(v)
		if k != "" {
			columns = append(columns, k)
		}
	}

	wrapper := dbinfo.NewQueryWrapper().Select(columns...).Eq(refer.KeyName(), id)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	return sqlfactory.FindOneByWrapper(wrapper, refer.DbName, refer.Name)
}

// FindByKey 根据条件查询多条
func (s *VirtualService) FindByKey(ctx *gin.Context, refer *dbinfo.TableInfo, fields []string, params map[string]interface{}, orders []dbinfo.OrderInfo) (bool, string, interface{}) {
	columns := []string{}
	for _, v := range fields {
		k := refer.GetFieldName(v)
		if k != "" {
			columns = append(columns, k)
		}
	}

	order := []dbinfo.OrderInfo{}
	for _, v := range orders {
		k := refer.GetFieldName(v.Field)
		if k != "" {
			order = append(order, v)
		}
	}

	wrapper := dbinfo.NewQueryWrapper().Select(columns...).AddOrder(order...)

	conditions := s.CreateCondition(ctx, refer, params)
	wrapper.ConditionGroup[0].Conditions = append(wrapper.ConditionGroup[0].Conditions, conditions...)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	return sqlfactory.FindListByWrapper(wrapper, refer.DbName, refer.Name)
}

// FindByKeyOne 根据条件查询单条
func (s *VirtualService) FindByKeyOne(ctx *gin.Context, refer *dbinfo.TableInfo, fields []string, params map[string]interface{}) (bool, string, interface{}) {
	columns := []string{}
	for _, v := range fields {
		k := refer.GetFieldName(v)
		if k != "" {
			columns = append(columns, k)
		}
	}

	wrapper := dbinfo.NewQueryWrapper().Select(columns...)

	conditions := s.CreateCondition(ctx, refer, params)
	wrapper.ConditionGroup[0].Conditions = append(wrapper.ConditionGroup[0].Conditions, conditions...)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	return sqlfactory.FindOneByWrapper(wrapper, refer.DbName, refer.Name)
}

// FindPage 分页查询
func (s *VirtualService) FindPage(ctx *gin.Context, refer *dbinfo.TableInfo, findByPageParam *dbinfo.FindByPageParam) (bool, string, interface{}) {
	if findByPageParam == nil {
		return false, "分页参数缺失", 8001
	}

	wrapper := dbinfo.NewQueryWrapper()

	if findByPageParam.LikeStr != "" {
		for _, field := range refer.Fields {
			if field.GsType != "varchar" {
				continue
			}

			if _, ok := LikeQueryIgnoreNameArray()[field.GsName]; ok {
				continue
			}

			likeWrapper := dbinfo.ConditionGroup{}
			likeWrapper.Type = dbinfo.CondTypeOr
			likeWrapper.Like(field.GsName, findByPageParam.LikeStr)
			wrapper.ConditionGroup = append(wrapper.ConditionGroup, &likeWrapper)
		}
	}

	if len(findByPageParam.Fields) > 0 {
		fields := []string{}
		for _, v := range findByPageParam.Fields {
			k := refer.GetFieldName(v)
			if k != "" {
				fields = append(fields, k)
			}
		}

		wrapper.Select(fields...)
	}

	conditions := s.CreateCondition(ctx, refer, findByPageParam.Conditions)
	wrapper.ConditionGroup[0].Conditions = append(wrapper.ConditionGroup[0].Conditions, conditions...)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	if len(findByPageParam.Orders) > 0 {
		wrapper.Orders = findByPageParam.Orders
	}

	order := []dbinfo.OrderInfo{}
	for _, v := range findByPageParam.Orders {
		k := refer.GetFieldName(v.Field)
		if k != "" {
			order = append(order, v)
		}
	}

	if len(order) == 0 {
		if refer.HasIndex() {
			v := dbinfo.OrderInfo{
				Field: dbinfo.FrameworkField("iIndex"),
				Order: "ASC",
			}
			order = append(order, v)
		}

		if refer.HasCreateDate() {
			v := dbinfo.OrderInfo{
				Field: dbinfo.FrameworkField("dCreateDate"),
				Order: "DESC",
			}
			order = append(order, v)
		}

		if refer.HasModifiedDate() {
			v := dbinfo.OrderInfo{
				Field: dbinfo.FrameworkField("dModifiedDate"),
				Order: "DESC",
			}
			order = append(order, v)
		}
	}

	wrapper.AddOrder(order...)

	return sqlfactory.FindPageByWrapper(wrapper, refer.DbName, refer.Name, findByPageParam.Page.Current, findByPageParam.Page.Size)
}

// FindAll 查询所有
func (s *VirtualService) FindAll(ctx *gin.Context, refer *dbinfo.TableInfo) (bool, string, interface{}) {
	wrapper := dbinfo.NewQueryWrapper()

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	if refer.HasIndex() {
		wrapper.AddOrder(dbinfo.OrderInfo{
			Field: dbinfo.FrameworkField("iIndex"),
			Order: "ASC",
		})
	}

	if refer.HasModifiedDate() {
		wrapper.AddOrder(dbinfo.OrderInfo{
			Field: dbinfo.FrameworkField("iIndex"),
			Order: "DESC",
		})
	}

	return sqlfactory.FindListByWrapper(wrapper, refer.DbName, refer.Name)
}

func (s *VirtualService) CreateCondition(ctx *gin.Context, refer *dbinfo.TableInfo, params map[string]interface{}) []*dbinfo.QueryCondition {
	if len(params) < 1 {
		return nil
	}

	result := []*dbinfo.QueryCondition{}
	for k, v := range params {
		fieldName := refer.GetFieldName(k)
		if fieldName != "" {
			result = append(result, dbinfo.QueryCondition{}.Eq(fieldName, v))
			continue
		}

		if strings.HasSuffix(k, "Like") {
			fieldName := refer.GetFieldName(k[0 : len(k)-4])
			if fieldName != "" {
				result = append(result, dbinfo.QueryCondition{}.Like(fieldName, v))
			}

			continue
		}

		if strings.HasSuffix(k, "St") {
			fieldName := refer.GetFieldName(k[0 : len(k)-2])
			if fieldName != "" {
				result = append(result, dbinfo.QueryCondition{}.Gt(fieldName, v))
			}

			continue
		}

		if strings.HasSuffix(k, "Ed") {
			fieldName := refer.GetFieldName(k[0 : len(k)-2])
			if fieldName != "" {
				result = append(result, dbinfo.QueryCondition{}.Lt(fieldName, v))
			}

			continue
		}

		if strings.HasSuffix(k, "Array") {
			fieldName := refer.GetFieldName(k[0 : len(k)-4])
			if fieldName != "" {
				result = append(result, dbinfo.QueryCondition{}.In(fieldName, v))
			}

			continue
		}

	}

	return result
}

// FindMax 查询最大值
func (s *VirtualService) FindMax(ctx *gin.Context, refer *dbinfo.TableInfo, field string, params map[string]interface{}) (bool, string, interface{}) {
	group := dbinfo.ConditionGroup{
		Conditions: s.CreateCondition(ctx, refer, params),
	}

	if refer.HasDelSign() {
		group.Conditions = append(group.Conditions, &dbinfo.QueryCondition{
			Field:    dbinfo.FrameworkField("iDelSign"),
			Operator: "=",
			Value:    0,
		})
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			group.Conditions = append(group.Conditions, &dbinfo.QueryCondition{
				Field:    dbinfo.FrameworkField("sCreator"),
				Operator: "=",
				Value:    CurrentLoginUserId(ctx),
			})
		}
	}

	array := []*dbinfo.ConditionGroup{&group}
	return sqlfactory.MaxValue(refer.DbName, refer.Name, field, array)
}

// FindMin 查询最小值
func (s *VirtualService) FindMin(ctx *gin.Context, refer *dbinfo.TableInfo, field string, params map[string]interface{}) (bool, string, interface{}) {
	group := dbinfo.ConditionGroup{
		Conditions: s.CreateCondition(ctx, refer, params),
	}

	if refer.HasDelSign() {
		group.Conditions = append(group.Conditions, &dbinfo.QueryCondition{
			Field:    dbinfo.FrameworkField("iDelSign"),
			Operator: "=",
			Value:    0,
		})
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			group.Conditions = append(group.Conditions, &dbinfo.QueryCondition{
				Field:    dbinfo.FrameworkField("sCreator"),
				Operator: "=",
				Value:    CurrentLoginUserId(ctx),
			})
		}
	}

	array := []*dbinfo.ConditionGroup{&group}
	return sqlfactory.MinValue(refer.DbName, refer.Name, field, array)
}

// FindHas 查询是否存在
func (s *VirtualService) FindHas(ctx *gin.Context, refer *dbinfo.TableInfo, field string, value interface{}) (bool, string, interface{}) {
	field = refer.GetFieldName(field)
	if field == "" {
		return false, "字段不存在: ", 5001
	}

	wrapper := dbinfo.NewQueryWrapper().Select(field).Eq(field, value)
	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	return sqlfactory.CountData(refer.DbName, refer.Name, wrapper)
}

// FindCount 查询数量
func (s *VirtualService) FindCount(ctx *gin.Context, refer *dbinfo.TableInfo, params map[string]interface{}) (bool, string, interface{}) {
	wrapper := dbinfo.NewQueryWrapper()

	conditions := s.CreateCondition(ctx, refer, params)
	wrapper.ConditionGroup[0].Conditions = append(wrapper.ConditionGroup[0].Conditions, conditions...)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 5) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	return sqlfactory.CountData(refer.DbName, refer.Name, wrapper)
}

// FindTree 查询树形结构数据
func (s *VirtualService) FindTree(ctx *gin.Context, refer *dbinfo.TableInfo, groupColumn, groupName string) (bool, string, interface{}) {
	if !refer.HasPid() {
		return false, "指定分组字段不存在！", 1001
	}

	//-- 从文件读取 --//
	var filePath string

	if groupName == "" {
		filePath = "./temp/cache/" + refer.Name + "/tree.txt"
	} else {
		filePath = "./temp/cache/" + refer.Name + "/Group_" + groupName + ".txt"
	}

	bl, _, data := jsonutil.FormFile(filePath, map[string]interface{}{})
	if bl {
		return true, "在文件中找到", data //返回结果
	}

	//-- 从数据库读取 --//
	var build strings.Builder
	build.WriteString("SELECT * FROM ")
	build.WriteString(refer.Name)

	build.WriteString(" WHERE ")
	build.WriteString(refer.KeyName())
	build.WriteString(" > 0")

	where := []interface{}{}
	if groupName != "" {
		build.WriteString(" AND ")
		build.WriteString(dbinfo.FrameworkField("sPath"))
		build.WriteString(" LIKE (")
		build.WriteString(" 	select CONCAT(a.")
		build.WriteString(dbinfo.FrameworkField("sPath"))
		build.WriteString(", '%')")
		build.WriteString(" 	from ")
		build.WriteString(refer.Name)
		build.WriteString(" a")

		if groupColumn != "" {
			field := refer.GetFieldName(groupColumn)
			build.WriteString(" 	where a.")
			build.WriteString(field) //指定字段作为分组标识
			build.WriteString(" = ?")
		} else if refer.HasOnlyign() { //启用唯一标识作为关键字
			build.WriteString(" 	where a.")
			build.WriteString(dbinfo.FrameworkField("sOnlyign")) //启用唯一标识作为关键字
			build.WriteString(" = ?")                            //启用唯一标识作为关键字
		} else {
			build.WriteString(" 	where a.")
			build.WriteString(dbinfo.FrameworkField("sName"))
			build.WriteString(" = ?")
		}

		build.WriteString(" )")
		where = append(where, groupName)
	}

	build.WriteString(" ORDER BY ")
	build.WriteString(dbinfo.FrameworkField("sPath"))

	txt := strings.Replace(build.String(), ", FROM ", " FROM ", -1)

	bl, msg, res := sqlfactory.FindList(refer.DbName, txt, where)
	if !bl {
		return bl, msg, res
	}

	if len(res.([]map[string]interface{})) < 1 {
		return false, "数据为空", 1004
	}

	rootValue := "00" //dbinfo.TableTreeRootValue[0]
	if groupName != "" {
		rootValue = res.([]map[string]interface{})[0][dbinfo.FrameworkField("sId")].(string) //分组查询情况下必须要一个根节点(因为已经path排序)
	}

	bl, msg, res = s.CreateTree(res, rootValue, dbinfo.FrameworkField("sId"), dbinfo.FrameworkField("sPid"), "childs")
	if !bl {
		return bl, msg, res
	}

	if len(res.([]interface{})) < 1 {
		return false, "数据转换后构造树型数据为空", 1005
	}

	jsonutil.ToFile(res, filePath) //保存到文件

	return true, "查询成功", res
}

/**
 * List转树形结构
 * @param source Map或切片结构
 * @param rootName
 * @param idFieldName
 * @param pIdFieldName
 * @param childFieldName
 * @return (bool, string, interface{}) 返回验证结果
 */
func (s *VirtualService) CreateTree(source interface{}, rootName, idFieldName, pIdFieldName, childFieldName string) (bool, string, interface{}) {
	if source == nil {
		return false, "没有数据无法进行树结构创建!", 5001
	}

	if strings.TrimSpace(idFieldName) == "" {
		return false, "对象字段中的编号属性名称必须提供!", 5002
	}

	if strings.TrimSpace(pIdFieldName) == "" {
		return false, "对象字段中的上级编号属性名称必须提供!", 5003
	}

	if strings.TrimSpace(childFieldName) == "" {
		return false, "对象字段中的子节点集合属性名称必须提供!", 5004
	}

	return s.createTreeByMap(source.([]map[string]interface{}), rootName, idFieldName, pIdFieldName, childFieldName)
	// sourceTypeName := reflect.TypeOf(source).String()
	// if strings.HasPrefix(sourceTypeName, "[]map[string]interface") {
	// 	return s.createTreeByMap(source.([]map[string]interface{}), rootName, idFieldName, pIdFieldName, childFieldName)
	// }

	// return s.createTreeByList(source.([]interface{}), rootName, idFieldName, pIdFieldName, childFieldName)
}

/**
 * List转树形结构
 * @param source Map结构
 * @param rootName
 * @param idFieldName
 * @param pIdFieldName
 * @param childFieldName
 * @return (bool, string, interface{}) 返回验证结果
 */
func (s *VirtualService) createTreeByMap(source []map[string]interface{},
	rootName, idFieldName, pIdFieldName, childFieldName string) (bool, string, interface{}) {
	if len(source) < 1 {
		return false, "没有数据无法进行树结构创建!", 5001
	}

	result := []interface{}{}

	rt := reflect.TypeOf(source[0])
	sourceTypeName := rt.String()

	isMap := strings.HasPrefix(sourceTypeName, "map[string]interface") //如果数据类型是Map则取值不能用反射方式

	if strings.TrimSpace(rootName) == "" {
		rootName = "00" //未指定就默认为'00'做根节点
	}

	//-- 将所有数据进行预分组存储,同时筛选出根节点 --//
	groupMap := map[string][]interface{}{} //待进行挂接的子分组
	allMap := map[string]interface{}{}
	for _, object := range source {
		groupName := ""
		if !isMap {
			groupName = reflectutil.GetFieldValue(object, pIdFieldName).(string)
		} else {
			groupName = object[pIdFieldName].(string)
		}

		if strings.TrimSpace(groupName) == "" {
			groupName = rootName //如果父节点信息为空,则默认为根节点
		}

		groupName = strings.TrimSpace(groupName) //所在组名

		sid := ""
		if isMap {
			sid = object[idFieldName].(string)
		} else {
			sid = (reflectutil.GetFieldValue(object, idFieldName)).(string)
		}

		allMap[sid] = object

		if rootName == groupName {
			result = append(result, object) //加入根节点列表
			continue
		}

		childs, ok := groupMap[groupName]
		if !ok {
			childs = []interface{}{}
			groupMap[groupName] = childs
		}

		childs = append(childs, object)
		groupMap[groupName] = childs
	}

	//--将所有分组寻找父节点--//
	for key, value := range groupMap {
		obj := allMap[key]
		if obj == nil {
			continue
		}

		typeName := reflect.TypeOf(obj).String()
		if strings.HasPrefix(typeName, "map[string]interface") {
			(obj.(map[string]interface{}))[childFieldName] = value
			continue
		}

		reflectutil.SetFieldValue(obj, childFieldName, value) // 设置子节点集合
	}

	return true, "构造成功!", result
}

/**
 * 查询组结构数据
 * @param ctx GinHttp上下文对象
 * @param refer 实体类
 * @param groupColumn 分组名(树节点)所在字段名
 * @param groupName 分组名(树节点)
 * @return (bool, string, interface{}) 返回验证结果
 */
func (s *VirtualService) FindByGroup(ctx *gin.Context, refer *dbinfo.TableInfo, groupColumn, groupName string) (bool, string, interface{}) {
	return s.FindTree(ctx, refer, groupColumn, groupName)
}

// ClearCache 清理指定用户的缓存
func (s *VirtualService) ClearCache(ctx *gin.Context, refer *dbinfo.TableInfo, cacheName, user string) (bool, string, interface{}) {
	cacheName = strings.TrimSpace(cacheName)
	if cacheName == "" {
		return false, "指定'缓存库名称'参数为空！", 7001
	}

	val, bl := ctx.Get("Controller")
	if val == nil || !bl {
		return true, "没有控制器对象！", 7002
	}

	user = strings.TrimSpace(user)
	if user != "" {
		user = user + "_"
	}

	filePath := AppPath() + "/temp/cache/" + refer.Name + "/" + user + cacheName

	bl, _ = fileutil.Del(filePath) //删除文件
	if !bl {
		return false, "清理失败！", 7004
	}

	Log.Info("清理缓存库:" + cacheName)

	return false, "清理失败！", 7002
}

/**
 * 添加数据到指定组下
 * 警告:对象必须符合树形结构要求,如:Id、Pid
 * @param ctx GinHttp上下文对象
 * @param refer 实体对象
 * @param groupName 分组字段名称(树节点)
 * @param groupValue 分组字段值(树节点)
 * @return (bool, string, interface{}) 返回验证结果
 */
func (s *VirtualService) AddToGroup(ctx *gin.Context, refer *dbinfo.TableInfo, groupName, groupValue string, data map[string]interface{}) (bool, string, interface{}) {
	if groupName == "" {
		return false, "节点参数不能为空!", 8001
	}

	if refer == nil {
		return false, "实体对象不能为空!", 8002
	}

	if !refer.HasPid() {
		return false, "指定分组字段不存在！", 8003
	}

	if dbinfo.FrameworkField("sId") != refer.KeyName() {
		return false, "实体类型没有Id字段,不符合格式要求!", 8004
	}

	if !refer.HasPid() {
		return false, "实体类型没有Pid字段,不符合格式要求!", 8005
	}

	//-- 查组所在记录编号 --//
	var build strings.Builder
	build.WriteString("SELECT ")
	build.WriteString(dbinfo.FrameworkField("sId"))
	build.WriteString(" FROM ")
	build.WriteString(refer.Name)
	build.WriteString(" WHERE ")
	build.WriteString(groupName)
	build.WriteString("=? LIMIT 0, 1")

	bl, msg, res := sqlfactory.FindColumn(refer.DbName, build.String(), groupValue)
	if !bl {
		return bl, msg, res
	}

	pid := res.(string)

	if pid == "" {
		return false, "指定组不存在,不能用此方法添加!", 8007
	}

	data[dbinfo.FrameworkField("sPid")] = pid // 父编号就是查出来的数据

	return s.AddCommon(ctx, refer, data)
}

// Add 添加数据
func (s *VirtualService) Add(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	if refer.HasPid() {
		return s.AddNode(ctx, refer, data)
	}

	return s.AddCommon(ctx, refer, data)
}

/**
 * 新增普通数据
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param data 数据
 * @return bool, string, interface{}
 */
func (s *VirtualService) AddCommon(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	data = refer.RemoveData(data, addRemoveNameArray()...) //清理不能由前端定义的字段

	iCode, err := refer.ValidAttr(data, addValidIgnoreNameArray()...) //对对象中的不为nil的属性检查限制
	if err != nil {
		return false, err.Error(), iCode + 7000
	}

	commons := refer.FilterByEntity(data, refer)

	commons = refer.SetDefault(commons, refer, false) //按对象中的属性添加默认值

	bl, msg, da := s.SupplyDbEntityAttrByAdd(ctx, commons, refer, "AAA", "") //补充除id外数据库实体类的数据--新增
	if !bl {
		return bl, msg, da
	}

	iCode, err = refer.ValidAttrByAdd(commons, refer) //对对象中的属性检查限制
	if err != nil {
		return false, err.Error(), iCode + 7020
	}

	bl, msg, da = s.ValidEntityRepeatByAdd(ctx, commons, refer) //验证新增数据是否存在重复
	if !bl {
		return bl, msg, da
	}

	bl, msg, da = s.SupplyDbEntityAttrByAdd(ctx, commons, refer, "", "") //补充数据库实体类的数据--新增
	if !bl {
		return bl, msg, da
	}

	bl, msg, res := sqlfactory.Add(refer.DbName, refer.Name, commons, refer.KeyName(), refer.IsAutoKey())
	if !bl {
		return bl, msg, res
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.Name + ".json"
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return bl, msg, res
}

/**
 * 新增树节点
 * @param ctx GinHttp上下文对象
 * @param refer 检查用数据结构
 * @param data 数据
 * @return bool, string, interface{}
 */
func (s *VirtualService) AddNode(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	refer.RemoveData(data, addRemoveNameArray()...) //清理不能由前端定义的字段

	iCode, err := refer.ValidAttr(data, addValidIgnoreNameArray()...) //对对象中的不为nil的属性检查限制
	if err != nil {
		return false, err.Error(), iCode + 7020
	}

	commons := refer.FilterByEntity(data, refer)

	commons = refer.SetDefault(commons, refer, false) //按对象中的属性添加默认值

	bl, msg, res := s.SupplyDbEntityAttrByAdd(ctx, commons, refer, "AAA", "") //补充除id外数据库实体类的数据--新增
	if !bl {
		return bl, msg, res
	}

	iCode, err = refer.ValidAttrByAdd(commons, refer) //对对象中的属性检查限制
	if err != nil {
		return false, err.Error(), iCode + 7020
	}

	bl, msg, res = s.ValidEntityRepeatByAdd(ctx, commons, refer) //验证新增数据是否存在重复
	if !bl {
		return bl, msg, res
	}

	bl, msg, res = s.SupplyDbEntityAttrByAdd(ctx, commons, refer, "", "") //补充除数据库实体类的数据--新增
	if !bl {
		return bl, msg, res
	}

	bl, msg, res = sqlfactory.Add(refer.DbName, refer.Name, commons, refer.KeyName(), false)
	if !bl {
		return bl, msg, res
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.Name + ".json"
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return bl, msg, res
}

// Adds 批量添加数据
func (s *VirtualService) Adds(ctx *gin.Context, refer *dbinfo.TableInfo, data []map[string]interface{}) (bool, string, interface{}) {
	// 这里可以添加业务逻辑校验

	// for _, item := range data {
	// 	result := sqlfactory.InsertData(refer.DbName, refer.Name, item)
	// 	if !result.Success {
	// 		return result
	// 	}

	// }

	return false, "执行失败: ", 5002
}

// Edit 更新数据
func (s *VirtualService) Edit(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	id, ok := data[refer.KeyName()] //记录编号值
	if !ok || id == "" {
		return s.Add(ctx, refer, data)
	}

	edition := -1 //记录版本号
	if temp, ok := data[dbinfo.FrameworkField("iVersion")]; ok {
		edition = temp.(int)
	}

	if fmt.Sprintf("%v", id) == "" {
		return false, "记录编号参数为空！", 7001
	}

	data = refer.HoldByEntity(refer, data)                  //按实体保留map中的数据
	data = refer.RemoveData(data, editRemoveNameArray()...) //清理不能由前端定义的字段

	if len(data) < 1 {
		return false, "更新操作提供的参数为空！", 7002
	}

	if refer.HasVersion() && (1 > edition) {
		return false, "记录版本号参数必须大于0！", 7003
	}

	var oldData map[string]interface{}
	if refer.HasRecordKey() { //如果存在RecordKey标识，则必须进行记录校验
		bl, msg, res := sqlfactory.FindById(refer.DbName, refer.Name, refer.KeyName(), data[refer.KeyName()], "")
		if !bl {
			return bl, msg, res
		}

		oldData = res.(map[string]interface{})
		nowKey := refer.CreateRecordKeyByMap(oldData, getRecordKeyJam())

		if nowKey != oldData[dbinfo.FrameworkField("sRecordKey")] {
			return false, "记录校验失败！", 7005
		}
	}

	stringutil.TrimAttribute(data) //清除对象各个属性的值的前后空格

	iCode, err := refer.ValidAttr(data, editValidIgnoreNameArray()...) //对对象中不为nil的属性检查限制
	if err != nil {
		return false, err.Error(), iCode + 7020
	}

	bl, msg, res := s.ValidEntityRepeatByEdit(ctx, refer, id, data) //验证更新数据是否存在重复
	if !bl {
		return bl, msg, res
	}

	//进行前端不可传递数据处理,如:修改者、修改时间等信息清理并赋值
	bl, msg, res = s.SupplyDbEntityAttrByEdit(ctx, data, refer)
	if !bl {
		return bl, msg, res
	}

	if refer.HasRecordKey() { //如果存在RecordKey标识，则必须重新对数据的检验字段进行生成
		for key, val := range data { //覆盖旧数据:警告oldData后面不能再用
			oldData[key] = val
		}

		data[dbinfo.FrameworkField("sRecordKey")] = refer.CreateRecordKeyByMap(oldData, recordKeyJam) //更新RecordKey
	}

	wrapper := dbinfo.NewQueryWrapper()
	wrapper.Eq(refer.KeyName(), id) //记录编号值

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)
	}

	if refer.HasCreator() {
		onlyCreator := !s.EnableTag(refer.Name, 6) //6个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆
		if onlyCreator {
			wrapper.Eq(dbinfo.FrameworkField("sCreator"), CurrentLoginUserId(ctx))
		}
	}

	bl, msg, res = sqlfactory.Edit(wrapper, refer.DbName, refer.Name, data)
	if !bl {
		return bl, msg, res
	}

	//清理缓存
	filePath := AppPath() + "/temp/cache/" + refer.Name
	fileutil.DelFiles(filePath, true) //删除整个文件夹

	return bl, msg, res
}

// Edits 批量更新数据
func (s *VirtualService) Edits(ctx *gin.Context, refer *dbinfo.TableInfo, updates []struct {
	Conditions []dbinfo.QueryCondition
	Data       map[string]interface{}
}) (bool, string, interface{}) {
	// 这里可以添加业务逻辑校验

	// for _, update := range updates {
	// 	wrapper := dbinfo.NewQueryWrapper()
	// 	for _, v := range update.Conditions {
	// 		wrapper.AddCondition(v.Field, v.Operator, v.Value)
	// 	}

	// 	result := sqlfactory.UpdateData(wrapper, refer.DbName, refer.Name, update.Data)
	// 	if !result.Success {
	// 		return result
	// 	}

	// }

	return false, "执行失败", 5002
}

// Del 删除数据
func (s *VirtualService) DelByWhere(ctx *gin.Context, refer *dbinfo.TableInfo, params map[string]interface{}) (bool, string, interface{}) {
	wrapper := dbinfo.NewQueryWrapper()

	conditions := s.CreateCondition(ctx, refer, params)
	wrapper.ConditionGroup[0].Conditions = append(wrapper.ConditionGroup[0].Conditions, conditions...)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)

		data := map[string]interface{}{
			dbinfo.FrameworkField("iDelSign"): 1,
		}

		return sqlfactory.Edit(wrapper, refer.DbName, refer.Name, data)
	}

	return sqlfactory.Del(wrapper, refer.DbName, refer.Name)
}

// Del 删除数据
func (s *VirtualService) Del(ctx *gin.Context, refer *dbinfo.TableInfo, params map[string]interface{}) (bool, string, interface{}) {
	id, ok := params[refer.KeyName()] //记录编号值
	if !ok || id == "" {
		return false, "记录编号参数为空！", 7001
	}

	wrapper := dbinfo.NewQueryWrapper()
	wrapper.Eq(refer.KeyName(), id) //记录编号值

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)

		data := map[string]interface{}{
			dbinfo.FrameworkField("iDelSign"): 1,
		}

		return sqlfactory.Edit(wrapper, refer.DbName, refer.Name, data)
	}

	return sqlfactory.Del(wrapper, refer.DbName, refer.Name)
}

// Deletes 批量删除数据
func (s *VirtualService) Dels(ctx *gin.Context, refer *dbinfo.TableInfo, ids []interface{}) (bool, string, interface{}) {
	if len(ids) < 1 {
		return false, "ids参数为空", 5001
	}

	wrapper := dbinfo.NewQueryWrapper().In(refer.KeyName(), ids)

	if refer.HasDelSign() {
		wrapper.Eq(dbinfo.FrameworkField("iDelSign"), 0)

		data := map[string]interface{}{
			dbinfo.FrameworkField("iDelSign"): 1,
		}

		return sqlfactory.Edit(wrapper, refer.DbName, refer.Name, data)
	}

	return sqlfactory.Del(wrapper, refer.DbName, refer.Name)
}

// Transaction 事务处理
func (s *VirtualService) Transaction(operations []*sqlfactory.Operation) (bool, string, interface{}) {
	// 这里可以添加业务逻辑校验
	return sqlfactory.Transaction(GetMainDb(), operations)
	// return &dbinfo.QueryResult{Success: true}
}

// 获取当前执行程序所在的绝对路径
func AppPath() string {
	exePath, err := os.Executable()
	if err != nil {
		return "./"
	}

	res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))

	return res
}

// 新增时需要排除的字段(不允许前端传入)
func addRemoveNameArray() []string {
	addRemoveNamesOnce.Do(func() {
		addRemoveNames = []string{
			dbinfo.FrameworkField("sId"),           //数据库表主键名称(字符串形式)
			dbinfo.FrameworkField("iId"),           //数据库表主键名称(自增长形式)
			dbinfo.FrameworkField("uId"),           //数据库表主键名称(UUID形式)
			dbinfo.FrameworkField("sCreator"),      //数据库表字段名称-创建人
			dbinfo.FrameworkField("dCreateDate"),   //数据库表字段名称-创建时间
			dbinfo.FrameworkField("sModifieder"),   //数据库表字段名称-修改人
			dbinfo.FrameworkField("dModifiedDate"), //数据库表字段名称-修改时间
			dbinfo.FrameworkField("iState"),        //数据库表字段名称-状态值
			dbinfo.FrameworkField("iIndex"),        //数据库表字段名称-排序值
			dbinfo.FrameworkField("iVersion"),      //数据库表字段名称-版本号
			dbinfo.FrameworkField("iDelSign"),      //数据库表字段名称-逻辑删除标识
		}
	})

	return addRemoveNames
}

// 取新增时检验的忽略字段
func addValidIgnoreNameArray() []string {
	addValidIgnoreNamesOnce.Do(func() {
		addValidIgnoreNames = []string{
			dbinfo.FrameworkField("sId"),           //数据库表主键名称(字符串形式)
			dbinfo.FrameworkField("iId"),           //数据库表主键名称(自增长形式)
			dbinfo.FrameworkField("uId"),           //数据库表主键名称(UUID形式)
			dbinfo.FrameworkField("sPath"),         //数据库表字段名称-主键路径名
			dbinfo.FrameworkField("sCreator"),      //数据库表字段名称-创建人
			dbinfo.FrameworkField("dCreateDate"),   //数据库表字段名称-创建时间
			dbinfo.FrameworkField("sModifieder"),   //数据库表字段名称-修改人
			dbinfo.FrameworkField("dModifiedDate"), //数据库表字段名称-修改时间
			dbinfo.FrameworkField("iState"),        //数据库表字段名称-状态值
			dbinfo.FrameworkField("iIndex"),        //数据库表字段名称-排序值
			dbinfo.FrameworkField("iVersion"),      //数据库表字段名称-版本号
			dbinfo.FrameworkField("iDelSign"),      //数据库表字段名称-逻辑删除标识
			dbinfo.FrameworkField("sRecordKey"),    //记录验证串字段名
		}
	})

	return addValidIgnoreNames
}

// 取修改时需要排除的字段(不允许前端传入)
func editRemoveNameArray() []string {
	editRemoveNamesOnce.Do(func() {
		editRemoveNames = []string{
			dbinfo.FrameworkField("sCreator"),      //数据库表字段名称-创建人
			dbinfo.FrameworkField("dCreateDate"),   //数据库表字段名称-创建时间
			dbinfo.FrameworkField("sModifieder"),   //数据库表字段名称-修改人
			dbinfo.FrameworkField("dModifiedDate"), //数据库表字段名称-修改时间
			dbinfo.FrameworkField("iState"),        //数据库表字段名称-状态值
			dbinfo.FrameworkField("iIndex"),        //数据库表字段名称-排序值
			dbinfo.FrameworkField("iDelSign"),      //数据库表字段名称-逻辑删除标识
			dbinfo.FrameworkField("sRecordKey"),    //记录验证串字段名
		}
	})

	return editRemoveNames
}

// 取修改时检验的忽略字段
func editValidIgnoreNameArray() []string {
	editValidIgnoreNamesOnce.Do(func() {
		editValidIgnoreNames = []string{
			dbinfo.FrameworkField("sPath"),         //数据库表字段名称-主键路径名
			dbinfo.FrameworkField("sCreator"),      //数据库表字段名称-创建人
			dbinfo.FrameworkField("dCreateDate"),   //数据库表字段名称-创建时间
			dbinfo.FrameworkField("sModifieder"),   //数据库表字段名称-修改人
			dbinfo.FrameworkField("dModifiedDate"), //数据库表字段名称-修改时间
			dbinfo.FrameworkField("iState"),        //数据库表字段名称-状态值
			dbinfo.FrameworkField("iIndex"),        //数据库表字段名称-排序值
			dbinfo.FrameworkField("iVersion"),      //数据库表字段名称-版本号
			dbinfo.FrameworkField("iDelSign"),      //数据库表字段名称-逻辑删除标识
			dbinfo.FrameworkField("sRecordKey"),    //记录验证串字段名
		}
	})

	return editValidIgnoreNames
}

// 取模糊查询时的忽略字段
func LikeQueryIgnoreNameArray() map[string]string {
	likeQueryIgnoreNamesOnce.Do(func() {
		likeQueryIgnoreNames = map[string]string{
			dbinfo.FrameworkField("sId"):           "", //数据库表主键名称(字符串形式)
			dbinfo.FrameworkField("iId"):           "", //数据库表主键名称(自增长形式)
			dbinfo.FrameworkField("uId"):           "", //数据库表主键名称(UUID形式)
			dbinfo.FrameworkField("sPath"):         "", //数据库表字段名称-主键路径名
			dbinfo.FrameworkField("sCreator"):      "", //数据库表字段名称-创建人
			dbinfo.FrameworkField("dCreateDate"):   "", //数据库表字段名称-创建时间
			dbinfo.FrameworkField("sModifieder"):   "", //数据库表字段名称-修改人
			dbinfo.FrameworkField("dModifiedDate"): "", //数据库表字段名称-修改时间
			dbinfo.FrameworkField("iState"):        "", //数据库表字段名称-状态值
			dbinfo.FrameworkField("iIndex"):        "", //数据库表字段名称-排序值
			dbinfo.FrameworkField("iVersion"):      "", //数据库表字段名称-版本号
			dbinfo.FrameworkField("iDelSign"):      "", //数据库表字段名称-逻辑删除标识
			dbinfo.FrameworkField("sRecordKey"):    "", //记录验证串字段名
		}
	})

	return likeQueryIgnoreNames
}

/**
 * 补充数据库实体类的数据--新增
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param selfId 自提供的编号,防止从序列中获取
 * @param idValuePrefix Id前缀
 * @return bool, string, interface{}
 */
func (s *VirtualService) SupplyDbEntityAttrByAdd(ctx *gin.Context, data map[string]interface{}, refer *dbinfo.TableInfo, selfId string, idValuePrefix string) (bool, string, interface{}) {
	if refer == nil {
		return false, "待存储的数据实体不能为nil", 1001
	}

	data = refer.SetDefault(data, refer, false) //对对象中添加了dataInfo注解的属性添加默认值

	LoginUserId := CurrentLoginUserId(ctx) //取当前登录用户编号
	date := time.Now()

	if refer.HasCreator() {
		data[dbinfo.FrameworkField("sCreator")] = LoginUserId // 设置当前操作用户
	}

	if refer.HasModifieder() {
		data[dbinfo.FrameworkField("sModifieder")] = LoginUserId // 设置当前操作用户
	}

	if refer.HasCreateDate() {
		data[dbinfo.FrameworkField("dCreateDate")] = date // 设置新增时间
	}

	if refer.HasModifiedDate() {
		data[dbinfo.FrameworkField("dModifiedDate")] = LoginUserId // 设置修改时间
	}

	if refer.HasIndex() {
		data[dbinfo.FrameworkField("iIndex")] = 1 // 设置排序值
	}

	if refer.HasState() {
		data[dbinfo.FrameworkField("iState")] = 1 // 设置状态值
	}

	if refer.HasVersion() {
		data[dbinfo.FrameworkField("iVersion")] = 1 // 设置版本号
	}

	if refer.HasDelSign() {
		data[dbinfo.FrameworkField("iDelSign")] = 0 // 设置逻辑删除标识
	}

	//--如果有Pid字段则进行部分处理--//
	if refer.HasPid() {
		pid := data[dbinfo.FrameworkField("sPath")]
		if (pid == nil) || (pid.(string) == "") { //如果Pid为空,则默认赋值'00'
			data[dbinfo.FrameworkField("sPath")] = "00"
		}
	}

	//-- 设置id --//
	newId := ""
	idName := refer.KeyName()

	if selfId != "" && !refer.IsAutoKey() { //有自定义id值
		data[dbinfo.FrameworkField(refer.KeyName())] = strings.ToUpper(selfId)
	} else if (selfId == "") && !refer.IsAutoKey() { //如果不是自增长,并且没有自定义id值,才能进行从序列中取新id的方法
		if refer.HasPath() { //对象中存在Path,则id需要按节点生成
			pid := data[dbinfo.FrameworkField("sPath")] //前面已经设置pid值

			bl, msg, da := sqlfactory.NewChildId(refer.DbName, refer.Name, idName, dbinfo.FrameworkField("sPid"), pid.(string))
			if !bl {
				return bl, msg, da
			}

			data[idName] = da.(string)
		} else if refer.KeyLen() == 32 { //按32位UUID设置值
			newId = strings.Replace(uuid.NewV4().String(), "-", "", -1) //取uuid
			data[idName] = newId
		} else if refer.KeyLen() == 22 { //按22位UUID设置值
			data[idName] = u64util.Get(idValuePrefix)
		} else if idValuePrefix == "" {
			newId = GetNewId(refer.KeyLen(), refer.Name)
			data[idName] = newId
		} else {
			iLength := refer.KeyLen() - len(idValuePrefix)
			newId = idValuePrefix + GetNewId(iLength, refer.Name)
			data[idName] = newId
		}
	}

	//--如果有path字段则进行部分处理--//
	if (newId != "") && refer.HasPath() {
		path := idToPath(newId)
		data[dbinfo.FrameworkField("sPath")] = path

		pid := data[dbinfo.FrameworkField("sPid")]
		if (pid == nil) || (pid.(string) == "") { //如果pid为空,则默认赋值'00'
			data[dbinfo.FrameworkField("sPid")] = "00"
		}
	}

	//--如果有recordKey字段则进行部分处理--//
	if refer.HasRecordKey() {
		key := refer.CreateRecordKey(data, getRecordKeyJam())
		if len(key) > 0 {
			data[dbinfo.FrameworkField("sRecordKey")] = key[0]
		}
	}

	return true, "补充数据完毕！", 1999
}

/**
 * 补充数据库实体类的数据--修改
 * @param ctx GinHttp上下文对象
 * @param data 待修改的数据
 * @param refer 参照结构体
 * @return bool, string, interface{}
 */
func (s *VirtualService) SupplyDbEntityAttrByEdit(ctx *gin.Context, data map[string]interface{}, refer *dbinfo.TableInfo) (bool, string, interface{}) {
	if len(data) < 1 {
		return false, "待修改的数据不能为nil", 1001
	}

	LoginUserId := CurrentLoginUserId(ctx) //取当前登录用户编号

	if refer.HasCreator() {
		delete(data, dbinfo.FrameworkField("sCreator")) // 清理,限制不允许修改创建人
	}

	if refer.HasCreateDate() {
		delete(data, dbinfo.FrameworkField("dCreateDate")) // 清理,限制不允许修改设置新增时间
	}

	if refer.HasDelSign() {
		delete(data, dbinfo.FrameworkField("iDelSign")) // 清理,限制不允许修改删除标识
	}

	if refer.HasModifieder() {
		data[dbinfo.FrameworkField("sModifieder")] = LoginUserId // 设置当前操作用户
	}

	if refer.HasModifiedDate() {
		data[dbinfo.FrameworkField("dModifiedDate")] = time.Now() // 设置修改时间
	}

	if refer.HasVersion() {
		data[dbinfo.FrameworkField("iVersion")] = data[dbinfo.FrameworkField("iVersion")].(int) + 1 // 设置版本号
	}

	if refer.HasDelSign() {
		data[dbinfo.FrameworkField("iDelSign")] = 0
	}

	//--如果有sRecordKey字段则进行部分处理,为提高效率,在edit中处理--//

	return true, "补充数据完毕！", 1999
}

/**
 * 验证新增数据是否存在重复
 * @param ctx GinHttp上下文对象
 * @param refer 参照结构体
 * @return bool, string, interface{}
 */
func (s *VirtualService) ValidEntityRepeatByAdd(ctx *gin.Context, data map[string]interface{}, refer *dbinfo.TableInfo) (bool, string, interface{}) {
	//-- 树形结构 --//
	if refer.HasPid() {
		return s.CommonCheckRepeatByAddAndTree(ctx, refer, data) //通用树型结构表添加数据时重复检查方法
	}

	//--不是树形数据则使用普通方法检查--//
	return s.CommonCheckRepeatByAdd(ctx, refer, data) //通用添加数据时重复检查方法
}

/**
 * 验证更新数据是否存在重复
 * @param ctx GinHttp上下文对象
 * @param refer 参照结构体
 * @param id 主键值
 * @param data 待修改的数据
 * @return bool, string, interface{}
 */
func (s *VirtualService) ValidEntityRepeatByEdit(ctx *gin.Context, refer *dbinfo.TableInfo, id interface{}, data map[string]interface{}) (bool, string, interface{}) {
	//-- 树形结构 --//
	if refer.HasPid() {
		return s.CommonCheckRepeatByEditAndTree(ctx, refer, data) //通用树型结构表添加数据时重复检查方法
	}

	//--不是树形数据则使用普通方法检查--//
	return s.CommonCheckRepeatByEdit(ctx, refer, id, data) //通用添加数据时重复检查方法
}

/**
 * 通用树型结构表添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @return bool, string, interface{}
 */
func (s *VirtualService) CommonCheckRepeatByAddAndTree(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	vName := data[dbinfo.FrameworkField("sPid")]
	if vName == nil {
		return false, "节点名称为空", 1001
	}

	name := vName.(string)

	var pid string
	vPid := data[dbinfo.FrameworkField("sPid")]
	if vPid != nil {
		pid = vPid.(string)
	} else {
		pid = "00"
	}

	if pid == "" {
		pid = "00"
	}

	where := make(map[string]interface{})

	//同一层节点下,展现名不能相同//
	var build strings.Builder
	build.WriteString("SELECT SUM(iCount) AS iCount FROM (")

	if refer.HasSign() {
		build.WriteString(" 	select SIGN(COUNT(1) * 10) as iCount from ${DbTableName}")
		build.WriteString(" 	where ")
		build.WriteString(dbinfo.FrameworkField("sSign"))
		build.WriteString(" =@")
		build.WriteString(dbinfo.FrameworkField("sSign"))
		build.WriteString(" UNION ALL ")

		where[dbinfo.FrameworkField("sSign")] = data[dbinfo.FrameworkField("sSign")]
	}

	build.WriteString(" 	select SIGN(COUNT(1)) as iCount from ${DbTableName}")
	build.WriteString(" 	where ${PidKey} = @Pid and ${TreeNodeName} = @Name")
	build.WriteString(") TMP")

	txt := build.String()
	txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
	txt = strings.Replace(txt, "${TableName}", refer.Name, -1)
	txt = strings.Replace(txt, "${PidKey}", dbinfo.FrameworkField("sPid"), -1)
	txt = strings.Replace(txt, "${TreeNodeName}", "00", -1)

	where["Pid"] = pid
	where["Name"] = name

	bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
	if !bl {
		return bl, msg, res
	}

	iCount := res.(int)

	if iCount != 0 {
		return false, "节点重复", 1003
	}

	return true, "节点未重复", 1999
}

/**
 * 通用树型结构表添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param id
 * @param name
 * @return bool, string, interface{}
 */
func (s *VirtualService) CommonCheckRepeatByEditAndTree(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	name := data[dbinfo.FrameworkField("sName")]
	if (name == nil) || (name == "") || (name == "<nil>") {
		return false, "节点名称为空", 1001
	}

	where := make(map[string]interface{})

	//同一层节点下,展现名不能相同//
	var build strings.Builder
	build.WriteString("SELECT SUM(iCount) AS iCount FROM (")

	if refer.HasSign() {
		build.WriteString(" 	select SIGN(COUNT(1) * 10) as iCount from ${DbTableName}")
		build.WriteString(" 	where ")
		build.WriteString(dbinfo.FrameworkField("sSign"))
		build.WriteString(" =@")
		build.WriteString(dbinfo.FrameworkField("sSign"))
		build.WriteString(" 	and ${Id} <> @Id")
		build.WriteString(" UNION ALL ")

		where[dbinfo.FrameworkField("sSign")] = data[dbinfo.FrameworkField("sSign")]
	}

	build.WriteString(" 	select SIGN(COUNT(1)) as iCount from ${DbTableName}")
	build.WriteString(" 	where ${Id} <> @Id")
	build.WriteString(" 	and ${PidKey} = (select a.${PidKey} from ${DbTableName} a where a.${Id} =@Id)")
	build.WriteString(" 	and ${TreeNodeName} =@Name")
	build.WriteString(") TMP")

	txt := build.String()
	txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
	txt = strings.Replace(txt, "${TableName}", refer.Name, -1)
	txt = strings.Replace(txt, "${Id}", refer.KeyName(), -1)
	txt = strings.Replace(txt, "${PidKey}", dbinfo.FrameworkField("sPid"), -1)
	txt = strings.Replace(txt, "${TreeNodeName}", "00", -1)

	where["Id"] = data[refer.KeyName()]
	where["Name"] = name

	bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
	if !bl {
		return bl, msg, res
	}

	iCount := res.(int)

	if iCount != 0 {
		return false, "节点重复", 1003
	}

	return true, "节点未重复", 1999
}

/**
 * 通用添加数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @return bool, string, interface{}
 */
func (s *VirtualService) CommonCheckRepeatByAdd(ctx *gin.Context, refer *dbinfo.TableInfo, data map[string]interface{}) (bool, string, interface{}) {
	vCheckRepeatCombination := getBusinessInfo(s.DbName, s.TableName).CheckRepeatCombination
	vCheckRepeatAlone := getBusinessInfo(s.DbName, s.TableName).CheckRepeatAlone

	k := 0

	//检查待新增内容是否存在重复数据(多字段组合重复即重复)集合
	if len(vCheckRepeatCombination) > 0 {
		checkRepeatCombination := vCheckRepeatCombination

		var build strings.Builder
		build.WriteString("SELECT COUNT(1) AS iCount FROM ${DbTableName} WHERE 1=1")

		var temp strings.Builder
		temp.WriteString("[")

		where := make(map[string]interface{})
		for _, value := range checkRepeatCombination {
			field := refer.GetField(value)
			build.WriteString(" AND ")
			build.WriteString(field.GsName)
			build.WriteString(" =@")
			build.WriteString(value)

			where[value] = data[field.GsName]

			temp.WriteString("、'")
			temp.WriteString(field.GsComment)
			temp.WriteString("'")
		}

		txt := strings.Replace(build.String(), "1=1 AND ", "", -1)
		txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
		txt = strings.Replace(txt, "${TableName}", refer.Name, -1)

		bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
		if !bl {
			return bl, msg, res
		}

		iCount := res.(int)

		if iCount != 0 {
			temp.WriteString("]组合发现数据重复")
			return false, strings.Replace(temp.String(), "、", "", 1), 1002
		}

		k++
	}

	//检查待新增内容是否存在重复数据(单独字段重复即重复)集合
	if len(vCheckRepeatAlone) > 0 {
		checkRepeatAlone := vCheckRepeatAlone

		var build strings.Builder
		build.WriteString("SELECT SUM(iCount) FROM (")

		where := make(map[string]interface{})
		for index, key := range checkRepeatAlone {
			field := refer.GetField(key)
			build.WriteString(" union all select (SIGN(COUNT(1)) * ")
			build.WriteString(fmt.Sprintf("%v", math.Pow(10, float64(index))))
			build.WriteString(") as iCount ")
			build.WriteString(" from ${DbTableName} ")
			build.WriteString(" where ")
			build.WriteString(field.GsName)
			build.WriteString("= @")
			build.WriteString(key)

			where[key] = data[field.GsName]
		}

		build.WriteString(") TMP")

		txt := strings.Replace(build.String(), " union all ", " ", 1)
		txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
		txt = strings.Replace(txt, "${TableName}", refer.Name, -1)

		bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
		if !bl {
			return bl, msg, res
		}

		iCount := res.(int)

		if iCount != 0 {
			var temp strings.Builder
			str := fmt.Sprintf("%0*d", len(checkRepeatAlone), iCount)
			array := []rune(str) //得到字符数组

			ml := len(checkRepeatAlone)
			for index, key := range checkRepeatAlone {
				i := len(fmt.Sprintf("%v", math.Pow(10, float64(index))))
				if array[ml-i] == 48 { // ASCII对应: '0' => 48, '1' => 49
					continue
				}

				field := refer.GetField(key)
				temp.WriteString("、'")
				temp.WriteString(field.GsComment)
				temp.WriteString("'")
			}

			temp.WriteString("存在重复")

			return false, strings.Replace(temp.String(), "、", "", 1), 1004
		}

		k++
	}

	if k == 0 {
		return true, "没有设定验证函数,通过", 1999
	}

	return true, "经验证,通过", 1999
}

/**
 * 通用更新数据时重复检查方法
 * @param ctx GinHttp上下文对象
 * @param refer
 * @param id
 * @param data
 * @return bool, string, interface{}
 */
func (s *VirtualService) CommonCheckRepeatByEdit(ctx *gin.Context, refer *dbinfo.TableInfo, id interface{}, data map[string]interface{}) (bool, string, interface{}) {
	vCheckRepeatCombination := getBusinessInfo(s.DbName, s.TableName).CheckRepeatCombination
	vCheckRepeatAlone := getBusinessInfo(s.DbName, s.TableName).CheckRepeatAlone

	k := 0

	//检查待修改内容是否存在重复数据(多字段组合重复即重复)集合
	if len(vCheckRepeatCombination) > 0 {
		checkRepeatCombination := vCheckRepeatCombination

		var build strings.Builder
		build.WriteString("SELECT COUNT(1) AS iCount FROM ${DbTableName} WHERE 1=1")

		var temp strings.Builder
		temp.WriteString("[")

		where := make(map[string]interface{})
		where[refer.KeyName()] = id
		build.WriteString(" AND ")
		build.WriteString(refer.KeyName())
		build.WriteString(" != @")
		build.WriteString(refer.KeyName())

		for _, value := range checkRepeatCombination {
			field := refer.GetField(value)
			build.WriteString(" AND ")
			build.WriteString(field.GsName)
			build.WriteString(" =@")
			build.WriteString(value)

			where[value] = data[field.GsName]

			temp.WriteString("、'")
			temp.WriteString(field.GsComment)
			temp.WriteString("'")
		}

		txt := strings.Replace(build.String(), "1=1 AND ", "", -1)
		txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
		txt = strings.Replace(txt, "${TableName}", refer.Name, -1)

		bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
		if !bl {
			return bl, msg, res
		}

		iCount := res.(int)

		if iCount != 0 {
			temp.WriteString("]组合发现数据重复")
			return false, strings.Replace(temp.String(), "、", "", 1), 1002
		}

		k++
	}

	//检查待修改内容是否存在重复数据(单独字段重复即重复)集合
	if len(vCheckRepeatAlone) > 0 {
		checkRepeatAlone := vCheckRepeatAlone

		var build strings.Builder
		build.WriteString("SELECT SUM(iCount) FROM (")

		where := make(map[string]interface{})
		where[refer.KeyName()] = id

		for index, key := range checkRepeatAlone {
			field := refer.GetField(key)
			build.WriteString(" union all select (SIGN(COUNT(1)) * ")
			build.WriteString(fmt.Sprintf("%v", math.Pow(10, float64(index))))
			build.WriteString(") as iCount ")
			build.WriteString(" from ${DbTableName} ")
			build.WriteString(" where ")
			build.WriteString(field.GsName)
			build.WriteString("= @")
			build.WriteString(key)
			build.WriteString(" and ")
			build.WriteString(field.GsName)
			build.WriteString(" != @")
			build.WriteString(refer.KeyName())

			where[key] = data[field.GsName]
		}

		build.WriteString(") TMP")

		txt := strings.Replace(build.String(), " union all ", " ", 1)
		txt = strings.Replace(txt, "${DbTableName}", refer.Name, -1)
		txt = strings.Replace(txt, "${TableName}", refer.Name, -1)

		bl, msg, res := sqlfactory.FindColumn(refer.DbName, txt, where)
		if !bl {
			return bl, msg, res
		}

		iCount := res.(int)

		if iCount != 0 {
			var temp strings.Builder
			str := fmt.Sprintf("%0*d", len(checkRepeatAlone), iCount)
			array := []rune(str) //得到字符数组

			ml := len(checkRepeatAlone)
			for index, key := range checkRepeatAlone {
				i := len(fmt.Sprintf("%v", math.Pow(10, float64(index))))
				if array[ml-i] == 48 { // ASCII对应: '0' => 48, '1' => 49
					continue
				}

				field := refer.GetField(key)
				temp.WriteString("、'")
				temp.WriteString(field.GsComment)
				temp.WriteString("'")
			}

			temp.WriteString("存在重复")

			return false, strings.Replace(temp.String(), "、", "", 1), 1004
		}

		k++
	}

	if k == 0 {
		return true, "没有设定验证函数,通过", 1999
	}

	return true, "经验证,通过", 1999
}

/**
 * 取控制开关
 * 控制开关,7个数的控制分别是:删除、修改、查询、导出、统计、步骤值可逆、物理删除
 * 其中前5个为'是否仅创建者可操作'后续为其它控制开关
 * @param moduleName 模块名称
 * @param i 位数,从右到左数,下标从1开始
 * @return
 */
func (s *VirtualService) EnableTag(moduleName string, i int) bool {
	data := getBusinessInfo(s.DbName, s.TableName).EnableTag
	result := data / int(math.Pow10(i-1)) % 10

	return result != 1 //1代表限制,非1才是不限制
}

// 取新ID
func GetNewId(iLength int, TableName string) string {
	module := globalvariable.Get("Module@TableKeyDao")
	if module == nil {
		return sequenceutil.Get()
	}

	resultValue := reflectutil.DoMethod(module, "GetNewId", 8, TableName)
	if len(resultValue) < 1 {
		Log.Error("反射调用TableKeyDao的GetNewId失败,返回结果与预期不符")
		return sequenceutil.Get()
	}

	return resultValue[0].Interface().(string)
}

// id转路径，并在每组之间插入 '/'
func idToPath(id string) string {
	var result strings.Builder
	length := len(id)

	result.WriteString("/00/")

	for i := 0; i < length; i += 2 {
		if i+2 <= length {
			result.WriteString(id[i : i+2])
		} else {
			result.WriteString(id[i:])
		}

		if i+2 < length {
			result.WriteString("/")
		}
	}

	result.WriteString("/")

	return result.String()
}

func getRecordKeyJam() string {
	recordKeyJamOnce.Do(func() {
		root := ""
		exePath, err := os.Executable()
		if err != nil {
			root = "."
		}

		root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

		entityFilePath := filepath.Join(root, "config/system.ini")

		if _, err := os.Stat(entityFilePath); os.IsNotExist(err) {
			return
		}

		cfg, err := ini.Load(entityFilePath)
		if err != nil {
			return
		}

		keys, err := cfg.GetSection("App")
		if err != nil {
			Log.Error("配置文件缺少配置组'App'")
			return
		}

		temp := keys.Key("RecordKeyJam")
		if temp == nil {
			return
		}

		recordKeyJam = temp.String()
	})

	if recordKeyJam == "" {
		recordKeyJam = "12345678"
	}

	return recordKeyJam
}

// 取业务信息
func getBusinessInfo(dbName, tableName string) *ServicBusinessInfo {
	root := ""
	exePath, err := os.Executable()
	if err != nil {
		root = "."
	}

	root, _ = filepath.EvalSymlinks(filepath.Dir(exePath))

	business := filepath.Join(root, "config/service/", dbName, tableName, ".json")

	var result ServicBusinessInfo

	if _, err := os.Stat(business); os.IsNotExist(err) {
		Log.Debug("业务配置文件不存在:", business)

		return &ServicBusinessInfo{
			EnableTag:              90000001,   //"控制操作,首位9不参与用7个数代表开关,0为不限制,1为限制",
			CheckRepeatCombination: []string{}, //"检查待新增内容是否存在重复数据(多字段组合重复即重复)集合,[]string",
			CheckRepeatAlone:       []string{}, //"检查待新增内容是否存在重复数据(单独字段重复即重复)集合,map[string]int,注意:int必须是1、10、100、1000"
		}
	}

	data, err := os.ReadFile(business)
	if err != nil {
		Log.Error("读取配置文件发生异常:", err)
		return nil
	}

	err = json.Unmarshal(data, &result)
	if err != nil {
		Log.Error("配置信息转实体发生异常:", err)
		return nil
	}

	return &result
}
